package com.darkflame.client.semantic;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Set;
import java.util.Map.Entry;
import java.util.logging.Logger;



public class RawQueryUtilities {


	static Logger Log = Logger.getLogger("sss.RawQueryUtilities");
	
	//prefix is the value (should always be capitalised) url is the key (any case)
	static HashMap<String, String> PrefixStore = new HashMap<String, String>();
	// locations

	//home directory
	//static String homeurl = GWT.getHostPageBaseURL();
	//public static final String textfetcher_url = homeurl+"text%20fetcher.php"; //$NON-NLS-1$
	
	
	public RawQueryUtilities() {
		
		

	}
	
	/** Should be run before use
	atm used only to add the default rdfs prefix**/
	public static void firstTimeSetUp(){
		
		//we add the default RDFS prefix on creation
		//as it will be at the top of the list, this should help speed a bit as its going to be one of the most used prefixs
		addPrefix("http://www.w3.org/2000/01/rdf-schema#", "rdfs:");
				
	}
	

	/*
	public static void GetTextFromRemoteURL(final String fileurl, final RequestCallback callback) {
				
		//if local just get file
		if (!fileurl.contains(":")){
			
			RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET,
					fileurl);
			
			// get the data from the file
			try {
				requestBuilder.sendRequest("",callback);
			} catch (RequestException e) {
				e.printStackTrace();
			}
		} else {
		//else
		RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.POST,
				textfetcher_url);
		
		// get the data from the file
		try {
			requestBuilder.sendRequest("FileURL=" +fileurl, callback);
		} catch (RequestException e) {
			e.printStackTrace();
		}
		}
	}
	*/
	
	public static HashMap<String, String> getPrefixs(){
		return PrefixStore;
		
	}
	
	/** returns the uri for the supplied short form uri if known, else returns just what was sent.
	 * 
	 * Note; Prefixs are internally all converted and searched as uppercase**/
	public static String getURI (String originalprefix)
	{
		
		String id = "";
		String prefix = originalprefix;
		
		//we ignore this request if the original string started with http:// https://  - those : are not supposed to be expanded
		if (originalprefix.startsWith("http://") || originalprefix.startsWith("https://")){
			
			return originalprefix;
			
		}
		
	
		
		
		//crop to :
		//we ignore, however, if a # or a " appears before it.
		// If a # or a " appears before the :, then its very unlikely to be a real prefix
		
		// dbpedia: is a real prefix  
		// however 
		// myontology.ntlist#"dbpedia: is a prefix" 
		// is not
		
		// In SSSNode we do a similar process for labels - 
		// it might be an idea to somehow combine this process's for a speed up?
		// (as its probably redundant looking for these positions twice?)

		int colonposition = prefix.indexOf(":");
		int hashposition = prefix.indexOf("#");
		int quoteposition = prefix.indexOf("\"");				
		
		//if ( prefix.contains(":")  ){
		if ( (colonposition>0) 
			 && ((colonposition<hashposition) || hashposition ==-1 )
			 && ((colonposition<quoteposition)|| quoteposition==-1 )
		    ){
			
			//Note; We should also ignore all : followed by a / in fact
			//This ensures file locations can be used like C:/  and not be missinterpreted as a prefix			
			if (originalprefix.charAt(colonposition+1)=='/'){
				Log.info("/ found after :, word being tested likely is a file url and not a prefix. eg c:/");
				return originalprefix;
			}
			
			Log.info("prefix found, expanding");
			
			id = prefix.split(":",2)[1];	 //the ,2 means we only split by the first : in the string
			 prefix = prefix.split(":",2)[0]+":";		   		
		} else {
			return originalprefix; //as it wasnt a prefix
		}
		
       if (PrefixStore.containsValue(prefix.toUpperCase())) {
    	  //(prefixs are always stored and fetched uppercase)
    	   
		//	Log.info("uri "+prefix+" present");
			
			Set<Entry<String, String>> setview = PrefixStore.entrySet();
			   for (Entry<String, String> entry : setview) {
			         if (entry.getValue().equals(prefix.toUpperCase())) {
			        	 return(entry.getKey()+id);
			         }
			     }		
			   Log.info("uri error in search from prefix");
			 return prefix;
		} else {
			//Log.info("prefix "+prefix+" not found;");
			return originalprefix;
		}
		
	}
	

	
	/** returns prefixed form of the id if it exists, else just the url.
	 * 
	 *  Note; Unlike the prefix (which is always uppercase) , the URL is currently case sensitive **/
	public static String getPrefix(String originalurl) {

		String id = "";
		String url = originalurl;
		
		//if it contains no slashes or dots, assume its already a prefix
		if (!(url.contains(".")||(url.contains("\\")))){
			Log.info(originalurl+" is already a prefix");
			return originalurl;
			
		}
		
		// remove < and > if present
		if (url.startsWith("<")) {
			url = url.substring(1, url.length() - 1);
		}
		
		//crop to # inclusive
		if (url.contains("#")){
			 id = url.split("#")[1];	
			url = url.split("#")[0]+"#";
		   		
		} 
		
		url = url.trim();		
		//Log.info("looking for prefix for url;" + url);

		if (PrefixStore.containsKey(url)) {
			
			//Log.info("prefix found;"+ PrefixStore.get(url)+id);
			return PrefixStore.get(url)+id;
		} else {
			//Log.info("prefix not found returning;"+originalurl);
			return originalurl;
		}

	}

	/** currently prefixs should be supplied ending with a colon, this should be fixed
	 * likewise urls need to end with #**/
	public static void addPrefix(String url, String prefix) {
		
		//we ignore this request if the original string started with http:// https://  - those : are not supposed to be expanded
				if (prefix.startsWith("http") || prefix.startsWith("https")){
					
					Log.severe("attempted to add http as a prefix. Thats just silly. Was supposed to be prefix for "+url );
					
					return;
					
				}
				
		
		//possible check for collisions? Later specs shouldn't automaticaly overwrite earlier ones!
		
	//	Log.info("adding  prefix for url;" + url+" with prefix "+prefix);
		PrefixStore.put(url.trim(), prefix.trim().toUpperCase());

		//Log.info("added prefix for url-" + PrefixStore.get(url));
	}

	public static ArrayList<String> splitToWords(String userQuery) {

		ArrayList<String> wordsList = new ArrayList<String>();

		int querylength = userQuery.length();
		int loc = 0;
		String currentWordSet = "";

		while (loc <= querylength) {

			char currentChar = userQuery.charAt(loc);
			// Log.info("char found-"+currentChar);
			if ((currentChar != ')') && (currentChar != '(')
					&& (currentChar != '|') && (currentChar != ' ')
					&& (currentChar != ' ') && (loc != (querylength))) {

				currentWordSet = currentWordSet + currentChar;
				loc++;
				continue;
			} else {

				// it marks the end of a word
				if (currentWordSet.length() > 0) {
					Log.info("word found-" + currentWordSet);
					wordsList.add(currentWordSet);
					currentWordSet = "";
				}
				loc++;

			}

		}

		return wordsList;
	}
	
	public static class NoURLsForWordException extends Exception
	{
	
	/**
		 * 
		 */
		private static final long serialVersionUID = -5784554526728691279L;
		
	String mistake;
	//----------------------------------------------
	// Default constructor - initializes instance variable to unknown
	  public NoURLsForWordException()
	  {
	    super();             // call superclass constructor
	    mistake = "No URLS found";
	  }
	  
	//-----------------------------------------------
	// Constructor receives some kind of message that is saved in an instance variable.
	  public NoURLsForWordException(String err)
	  {
	    super(err);     // call super class constructor
	    mistake = err;  // save message
	  }
	  
	//------------------------------------------------  
	// public method, callable by exception catcher. It returns the error message.
	  public String getError()
	  {
	    return mistake;
	  }
	}
	  /*
	public static SssUrlPropertySet getURLsetForWord(String fullPropertyIndex,
			String Word)throws NoURLsForWordException {
		
		ArrayList<String> urlSet = new ArrayList<String>();
		String predicate = "";
		String value = "";
		// adjust word to pre/value
		if (Word.contains(";")) {

			predicate = Word.split(";")[0];
			value = Word.split(";")[1];

			// add quotes if needed if its just a string being looked for
			if (!(predicate.startsWith("<") || predicate.contains(":"))) {

				predicate = "\"" + predicate + "\"";
			} else {
				predicate = getPrefix(predicate);
			}
			
			if (!(value.startsWith("<")     || value.contains(":"))) {
				value = "\"" + value + "\"";
			}else {
				value = getPrefix(value);
			}
			// --

			Word = predicate + " " + value;

		} else {
			// add quotes if needed
			if (!(Word.startsWith("<") || Word.contains(":"))) {
				Word = "\"" + Word + "\"";
			} else {
				Word = getPrefix(Word);
			}
			// --
			predicate = "rdfs:subClassOf";
			Word = predicate + " " + Word;
		}

		Log.info("searching for word:" + Word);

		int startHere = 0;

		while (startHere < fullPropertyIndex.length()) {
			// find next position of word

			int wordIndex = fullPropertyIndex.indexOf(Word+";", startHere);
			int wordIndex2 = fullPropertyIndex.indexOf(Word+".", startHere);
			//earliest positive hit
			wordIndex = smallestPositiveNumber(wordIndex,wordIndex2);
			
			
			
			Log.info("wordIndex=:" + wordIndex + " "
					+ fullPropertyIndex.charAt(wordIndex));

			// try small case
			if (wordIndex == -1) {
				wordIndex = fullPropertyIndex.indexOf(Word.toLowerCase()+";"); // doesnt
																			// work
																			// right
				wordIndex2 = fullPropertyIndex.indexOf(Word.toLowerCase()+"."); 
				
				wordIndex = smallestPositiveNumber(wordIndex,wordIndex2);
				
				Log.info("lower case wordIndex=:" + wordIndex + " "
						+ fullPropertyIndex.charAt(wordIndex));

				if (wordIndex == -1) {
					Log.info("no matchs found for |"+Word+"|");
					//if none found at all
					if (urlSet.size()==0){
					throw new NoURLsForWordException("no matchs found");
					}
					break;
				}
			}

			// backtrack to last .
			int lastStatementStart = fullPropertyIndex.lastIndexOf(">.",
					wordIndex);
			int lastStatementStart2 = fullPropertyIndex.lastIndexOf("\".",
					wordIndex);
			int lastStatementStart3 = fullPropertyIndex.lastIndexOf(" .",
					wordIndex);
			Log.info("lastStatementStart =:" + lastStatementStart + " =:"
					+ lastStatementStart2 + " =:" + lastStatementStart3);
			if ((lastStatementStart2 != -1)
					&& (lastStatementStart2 > lastStatementStart)) {
				lastStatementStart = lastStatementStart2;
			}
			if ((lastStatementStart3 != -1)
					&& (lastStatementStart3 > lastStatementStart)) {
				lastStatementStart = lastStatementStart3;
			}

			// default to start
			if (lastStatementStart == -1) {
				lastStatementStart = 0;
			}
			Log.info("lastStatementStart =:" + lastStatementStart);

			// get next url (should end in >)
			int urlStart = fullPropertyIndex.indexOf("http://",
					lastStatementStart);
			int urlEnd = fullPropertyIndex.indexOf(" ", urlStart);

			String url = fullPropertyIndex.substring(urlStart, urlEnd);
			Log.info("urlStart =:" + urlStart + " "
					+ fullPropertyIndex.charAt(urlStart));
			Log.info("urlEnd =:" + urlEnd + " "
					+ fullPropertyIndex.charAt(urlEnd));

			Log.info("words url =:" + url);
			// add to set
			urlSet.add(url);
			// update post
			startHere = wordIndex + Word.length();
		}
		// loop

		SssUrlPropertySet newset = new SssUrlPropertySet(urlSet,predicate,value);
		
		return newset;
	}
*/
	private static int smallestPositiveNumber(int wordIndex, int wordIndex2) {
		
		if (wordIndex<0){
			return wordIndex2;
		}
		if (wordIndex2<0){
			return wordIndex;
		}
		
		return Math.min(wordIndex, wordIndex2);
		
	}
	
	/** strips the quotes only from the start and end of a string **/
	public static String stripQuotes(String stringToStrip) {
		
		
		if (stringToStrip.startsWith("\"") && stringToStrip.endsWith("\"")){
			
			stringToStrip = stringToStrip.substring(1,stringToStrip.length()-1);
			Log.info("striped quotes from start and end:"+stringToStrip);
			
		}
		return stringToStrip;
	}
	
	/**returns the smallest non-negative number
	 * useful for finding the earliest position of something in a string...if its present at all
	 * 
	 *  returns -1 if not found any above zero */
	public static int smallestNonNegative(int... Numbers){
				
		int smallest = Integer.MAX_VALUE; //everything should be smaller then this!
		
		 for ( int num : Numbers )           
		 {
			 if (num!=-1 && num<smallest){
				 smallest=num;
			 }
			 			 
		 }
		
		 if (smallest==Integer.MAX_VALUE){
			 smallest=-1;
		 }
		
		return smallest;
		
	}
}
